#include "file_priorite.hpp"
#include <cstring>

/* Définition des structures
struct item_prio {
    Noeud* n;
    int val;
}

struct file_prio {
    int ind_min;
    int capa;
    int nb_items;
    item_prio** file;
}
 */

// Fonctions Internes

/*  Ajout d'un item
    Recherche d'un item
    Recherche de l'indice du min
    Tassage du tableau
 */

item_prio * initItem(Noeud* n, int val) {
    item_prio * ip;

    ip = (item_prio*) malloc(sizeof (item_prio));

    ip->n = n;
    ip->val = val;

    return ip;
}

void agrandirFile(file_prio* fp, bool verbose) {
    if (verbose) {
        cout << endl << "Dans agrandirFile()" << endl << "nb_items : " << fp->nb_items << "/ capa_arcs : " << fp->capa << endl;
    }

    if (fp->file == NULL) {
        fp->capa = 1;
        fp->file = (item_prio**) malloc(fp->capa * sizeof (item_prio*));
    } else if (fp->nb_items == fp->capa) {
        if (fp->capa == 0) {
            fp->capa = 1;
            fp->file = (item_prio**) malloc(fp->capa * sizeof (item_prio*));
        } else {
            fp->capa *= 2;
            fp->file = (item_prio**) realloc(fp->file, fp->capa*sizeof(item_prio*));
        }
    }
}

void rechercheMin(file_prio * fp, bool verbose) {
    int ind_min = 0;

    if (verbose) {
        cout << endl << "Dans rechercheMin() de file_prio" << endl;
    }

    for (int i = 0; i < fp->nb_items; i++) {

        if (verbose) {

            cout << "Noeud en compa : " << fp->file[i]->n->nom << " - val:" << fp->file[i]->val << endl;
        }

        if (fp->file[ind_min]->val == -1) {
            if (verbose) {
                cout << "la valeur en ind_min est -1" << endl;
            }
            if (fp->file[i]->val > -1)
                ind_min = i;
        } else {
            if (fp->file[i]->val > -1) {
                if (verbose) {
                    cout << "la valeur en ind_min est positive" << endl;
                }
                if (fp->file[i]->val < fp->file[ind_min]->val) {
                    ind_min = i;
                }
            }
        }
    }

    if (verbose) {
        cout << "Fin de rechercheMin()" << endl;
    }

    fp->ind_min = ind_min;
}

void ajoutItem(file_prio * fp, item_prio * ip, bool verbose) {
    if (verbose) {
        cout << "Dans ajoutItem()" << endl;
        cout << "    l'item à ajouter est " << ip->n->nom << endl;
    }

    agrandirFile(fp, verbose);

    if (verbose) {
        cout << "agrandirFile() ok" << endl;
    }

    if (verbose) {
        cout << "nb_items : " << fp->nb_items << endl;
        cout << "fp->file == " << (fp->file == NULL ? "NULL" : "not NULL") << endl;

    }

    fp->file[fp->nb_items] = ip;

    if (verbose) {
        cout << "dans file_prio, a " << fp->nb_items << ", il y a " << (fp->file[fp->nb_items] == NULL ? "NULL" : fp->file[fp->nb_items]->n->nom) << endl;
    }

    fp->nb_items++;

    rechercheMin(fp, verbose);

    if(verbose)
        cout << "Fin de ajoutItem()" << endl;
}

int rechercheNoeud(file_prio *fp, Noeud* n) {
    for (int i = 0; i < fp->nb_items; i++) {
        if (strcmp(fp->file[i]->n->nom, n->nom) == 0)
            return i;
    }

    return -1;
}

void tassageFile(file_prio *fp, bool verbose) {
    
    if(verbose) {
        cout << "Avant tassage()" << endl;
        
        cout << " nb_items : " << fp->nb_items << endl;
        
        for(int i = 0; i < fp->nb_items; i++)
            cout << "  " << i << " : " << (fp->file[i] != NULL ? fp->file[i]->n->nom : "NULL") << endl;
    }

    while (fp->file[fp->nb_items - 1] == NULL) {
        fp->nb_items--;
    }
    
    for(int i = 0; i < fp->nb_items ; i++) {
        if(fp->file[i] == NULL) {
            fp->file[i] = fp->file[fp->nb_items-1];
            fp->nb_items--;
        }
    }
    
    if(verbose) {
        cout << "Juste avant sortie de tassage()" << endl;
        
        cout << " nb_items : " << fp->nb_items << endl;
        
        for(int i = 0; i < fp->nb_items; i++)
            cout << "  " << i << " : " << (fp->file[i] != NULL ? fp->file[i]->n->nom : "NULL") << endl;
    }

    /*
    item_prio ** file_tmp = (item_prio**) malloc (sizeof(item_prio*)*fp->capa);


    for (int i = 0; i < fp->nb_items; i++) {
        if (fp->file[i] != NULL) {
            file_tmp[elem] = fp->file[i];
            elem++;
        }
    }


    for(int i = 0; i < fp->nb_items; i++) {
        if(fp->file[i] != NULL)
            free(fp->file[i]);
    }

    free(fp->file);

    fp->file = file_tmp;
*/
    rechercheMin(fp, verbose);
}

// Fonctions accessibles en dehors du module

file_prio * initFilePrio(bool verbose) {
    file_prio * fp = (file_prio*) malloc(sizeof (file_prio));

    fp->capa = 1;
    fp->nb_items = 0;
    fp->ind_min = 0;
    fp->file = NULL;

    return fp;
}

void ajoutPriorite(file_prio * fp, Noeud* n, int val, bool verbose) {
    if (verbose) {
        cout << endl << "Dans ajoutPriorité()" << endl;
    }

    item_prio* ip = initItem(n, val);

    if (verbose) {
        cout << "ip Init : name " << ip->n->nom << " - val : " << ip->val << endl;
    }

    ajoutItem(fp, ip, verbose);
}

Noeud* enleveMin(file_prio* fp, bool verbose) {

    item_prio * ip_min = fp->file[fp->ind_min];
    Noeud* n_min = ip_min->n;

    free(ip_min);

    fp->file[fp->ind_min] = NULL;

    tassageFile(fp, verbose);
    rechercheMin(fp, verbose);

    return n_min;
}

void diminuePriorite(file_prio* fp, Noeud* n, int val, bool verbose) {
    int ind = rechercheNoeud(fp, n);

    fp->file[ind]->val = val;

    rechercheMin(fp, verbose);
}

bool contientElem(file_prio* fp, Noeud* n) {
    return rechercheNoeud(fp, n) != -1;
}

bool fileVide(file_prio* fp) {
    return fp->nb_items == 0;
}

void testamentFile(file_prio* fp) {
    for (int i = 0; i < fp->nb_items; i++) {
        fp->file[i]->n = NULL;
        fp->file[i]->val = 0;
        free(fp->file[i]);
    }
}

